﻿using Onshi.POS.Modelo.Entidades;
using Onshi.POS.Modelo.Enumeradores;
using Onshi.POS.Repositorios;
using Onshi.POS.Articulos.Vistas;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Mail;
using System.Text;
using Onshi.POS.Modelo.Objectos;
using System.Data;

namespace Onshi.POS.Articulos
{
    public class ArticulosAltaModificacionEstandarPresentador
    {
        #region Constructores

        public ArticulosAltaModificacionEstandarPresentador(IArticulosAltaModificacionEstandar vista)
        {
            this.vista = vista;
        }

        #endregion

        #region Atributos

        private IArticulosAltaModificacionEstandar vista;

        #endregion

        #region Propiedades

        private RepositorioProveedores RepositorioProveedores
        {
            get { return new RepositorioProveedores(); }
        }

        private RepositorioCamposPersonalizadosArticulos RepositorioCamposPersonalizadosArticulos
        {
            get { return new RepositorioCamposPersonalizadosArticulos(); }
        }

        private RepositorioEventos RepositorioEventos
        {
            get { return new RepositorioEventos(); }
        }

        private RepositorioListasPreciosVentas RepositorioListasPreciosVentas
        {
            get { return new RepositorioListasPreciosVentas(); }
        }

        private RepositorioListasPreciosCompras RepositorioListasPreciosCompras
        {
            get { return new RepositorioListasPreciosCompras(); }
        }

        private RepositorioArticulos RepositorioArticulos
        {
            get { return new RepositorioArticulos(); }
        }

        private RepositorioSubRubrosArticulos RepositorioSubRubrosArticulos
        {
            get { return new RepositorioSubRubrosArticulos(); }
        }

        private RepositorioTiposComisionesArticulos RepositorioTiposComisionesArticulos
        {
            get { return new RepositorioTiposComisionesArticulos(); }
        }

        private RepositorioTiposCostosArticulos RepositorioTiposCostosArticulos
        {
            get { return new RepositorioTiposCostosArticulos(); }
        }

        private RepositorioTiposImpuestosArticulos RepositorioTiposImpuestosArticulos
        {
            get { return new RepositorioTiposImpuestosArticulos(); }
        }

        private RepositorioTiposArticulos RepositorioTiposArticulos
        {
            get { return new RepositorioTiposArticulos(); }
        }

        private RepositorioMarcas RepositorioMarcas
        {
            get { return new RepositorioMarcas(); }
        }

        private RepositorioDescuentosRecargosFechasHoras RepositorioPromociones
        {
            get { return new RepositorioDescuentosRecargosFechasHoras(); }
        }

        private RepositorioDescuentosRecargosCantidades RepositorioDescuentosRecargos
        {
            get { return new RepositorioDescuentosRecargosCantidades(); }
        }

        private RepositorioUsuarios RepositorioUsuarios
        {
            get { return new RepositorioUsuarios(); }
        }

        private RepositorioPermisos RepositorioPermisos
        {
            get { return new RepositorioPermisos(); }
        }

        private RepositorioRegistros RepositorioRegistros
        {
            get { return new RepositorioRegistros(); }
        }

        private RepositorioUbicaciones RepositorioUbicaciones
        {
            get { return new RepositorioUbicaciones(); }
        }

        private RepositorioConfiguraciones RepositorioConfiguraciones
        {
            get { return new RepositorioConfiguraciones(); }
        }

        #endregion

        #region Metodos

        public void Inicializar()
        {
            var configuracion = RepositorioConfiguraciones.Devolver();
            if (configuracion == null)
                throw new Exception("La configuración no existe");
            vista.ConfiguracionImagen = configuracion.Imagen;
            var ubicaciones = RepositorioUbicaciones.DevolverTodos();
            vista.ListadoUbicaciones = ubicaciones;
            vista.VariantesModificado = false;
            vista.ExistenciasModificado = false;
            if (vista.IdArticulo != 0)
            {
                var articulo = RepositorioArticulos.DevolverPorId(vista.IdArticulo, true);
                if (articulo == null)
                    throw new Exception("El artículo no existe");
                vista.IdSubRubroArticulo = articulo.SubRubro.Id;
                vista.IdMarca = articulo.Marca.Id;
                vista.IdDescuentoRecargoCantidad = articulo.DescuentoRecargoCantidad.Id;
                vista.IdDescuentoRecargoFechaHora = articulo.DescuentoRecargoFechaHora.Id;
                vista.IdTipoComisionArticulo = articulo.TipoComision.Id;
                vista.IdTipoImpuestoArticulo = articulo.TipoImpuesto.Id;
                vista.IdTipoCostoArticulo = articulo.TipoCosto.Id;
                vista.Codigo = articulo.Codigo;
                vista.Nombre = articulo.Nombre;
                vista.Comision = articulo.Comision;
                vista.ComisionMaxima = articulo.ComisionMaxima;
                vista.ExistenciaMinima = articulo.ExistenciaMinima;
                vista.ExistenciaMaxima = articulo.ExistenciaMaxima;
                vista.Observaciones = articulo.Observaciones;
                vista.Imagen = articulo.Imagen;
                vista.ListadoCamposPersonalizados = articulo.CamposPersonalizados;
                vista.ListadoListasPreciosVentas = articulo.ListasPreciosVentas;
                vista.ListadoListasPreciosCompras = articulo.ListasPreciosCompras;
                vista.ListadoProveedores = articulo.Proveedores;

                var variantes = articulo.Variantes.Where(x => !x.EstaEliminado).ToList();
                vista.ListadoVariantes = variantes;

                var listadoVariantes = ArticuloTipoSeleccion.GenerarListado(variantes, ubicaciones, articulo.Existencias);
                vista.TablaSeleccion = ArticuloTipoSeleccion.GenerarTabla(listadoVariantes, true, true);
                vista.ListadoSeleccion = listadoVariantes;

                vista.ListadoExistencias = articulo.Existencias;
                vista.Existencia = articulo.Existencias.Where(x => !x.EstaEliminado).Sum(x => x.Cantidad);
            }
            else
            {
                vista.Iva = configuracion.Iva;
                var listadoCamposPersonalizados = new List<ArticuloCampoPersonalizadoArticulo>();
                foreach (var item in RepositorioCamposPersonalizadosArticulos.DevolverTodos())
                    listadoCamposPersonalizados.Add(new ArticuloCampoPersonalizadoArticulo()
                    {
                        Entidad = item,
                        Valor = String.Empty
                    });
                vista.ListadoCamposPersonalizados = listadoCamposPersonalizados;

                var listadoListasPreciosVentas = new List<ArticuloListaPrecioVenta>();
                foreach (var item in RepositorioListasPreciosVentas.DevolverTodos())
                    listadoListasPreciosVentas.Add(new ArticuloListaPrecioVenta()
                    {
                        Entidad = item,
                        Valor = 0
                    });
                vista.ListadoListasPreciosVentas = listadoListasPreciosVentas;

                var listadoListasPreciosCompras = new List<ArticuloListaPrecioCompra>();
                foreach (var item in RepositorioListasPreciosCompras.DevolverTodos())
                    listadoListasPreciosCompras.Add(new ArticuloListaPrecioCompra()
                    {
                        Entidad = item,
                        Valor = 0
                    });
                vista.ListadoListasPreciosCompras = listadoListasPreciosCompras;

                vista.ListadoVariantes = new List<ArticuloVariante>();
                vista.ListadoSeleccion = new List<ArticuloExistencia>();
                vista.ListadoProveedores = new List<Proveedor>();

                var listadoVariantes = ArticuloTipoSeleccion.GenerarListado(new List<ArticuloVariante>(), ubicaciones, new List<ArticuloExistencia>());
                vista.TablaSeleccion = ArticuloTipoSeleccion.GenerarTabla(listadoVariantes, true, true);
                vista.ListadoSeleccion = listadoVariantes;

                vista.ListadoExistencias = new List<ArticuloExistencia>();
                vista.Existencia = 0;
            }
        }

        public void Aceptar()
        {
            var usuario = RepositorioUsuarios.DevolverPorId(vista.IdUsuarioSistema);
            if (usuario == null)
                throw new Exception("El usuario no existe");
            if (vista.IdArticulo == 0)
            {
                if (!usuario.Perfil.Permisos.Exists(x => x.Id == (Byte)EnumPermisos.ArticulosAlta))
                    throw new Exception("Permisos insuficientes");
            }
            else if (!usuario.Perfil.Permisos.Exists(x => x.Id == (Byte)EnumPermisos.ArticulosModificacion))
                throw new Exception("Permisos insuficientes");

            if (vista.IdSubRubroArticulo == 0)
                throw new Exception("El sub rubro no puede quedar vacío");
            if (vista.IdMarca == 0)
                throw new Exception("La marca no puede quedar vacía");
            if (vista.IdDescuentoRecargoCantidad == 0)
                throw new Exception("Los descuentos y recargos automáticos no pueden quedar vacíos");
            if (vista.IdTipoComisionArticulo == 0)
                throw new Exception("El tipo de comisión no puede quedar vacío");
            if (vista.IdTipoImpuestoArticulo == 0)
                throw new Exception("El tipo de impuesto no puede quedar vacío");
            if (vista.IdTipoCostoArticulo == 0)
                throw new Exception("El tipo de costo no puede quedar vacío");
            if (vista.IdDescuentoRecargoFechaHora == 0)
                throw new Exception("La promoción no puede quedar vacía");
            if (String.IsNullOrWhiteSpace(vista.Codigo))
                throw new Exception("El código no puede quedar vacío");
            if (String.IsNullOrWhiteSpace(vista.Nombre))
                throw new Exception("El nombre no puede quedar vacío");
            if (vista.ExistenciaMinima < 0)
                throw new Exception("La existencia mínima no puede ser menor a cero");
            if (vista.ExistenciaMaxima < 0)
                throw new Exception("La existencia máxima no puede ser menor a cero");
            if (vista.ExistenciaMinima > 0)
                if (vista.ExistenciaMinima >= vista.ExistenciaMaxima)
                    throw new Exception("La existencia mínima no puede ser mayor o igual a la existencia máxima");
            if (vista.Costo < 0)
                throw new Exception("El costo no puede ser menor a cero");
            if (vista.Iva < 0)
                throw new Exception("El I.V.A. no puede ser menor a cero");
            if (vista.Impuesto < 0)
                throw new Exception("El impuesto no puede ser menor a cero");

            Articulo articulo;
            if (vista.IdArticulo != 0)
            {
                articulo = RepositorioArticulos.DevolverPorId(vista.IdArticulo, true);
                if (articulo == null)
                    throw new Exception("El artículo no existe");
            }
            else
                articulo = new Articulo();

            articulo.Tipo = RepositorioTiposArticulos.DevolverPorId((Byte)EnumTiposArticulos.Estandar);
            if (articulo.Tipo == null)
                throw new Exception("El tipo de artículo no existe");
            articulo.SubRubro = RepositorioSubRubrosArticulos.DevolverPorId(vista.IdSubRubroArticulo);
            if (articulo.SubRubro == null)
                throw new Exception("El sub rubro no existe");
            articulo.Marca = RepositorioMarcas.DevolverPorId(vista.IdMarca);
            if (articulo.Marca == null)
                throw new Exception("La marca no existe");
            articulo.DescuentoRecargoCantidad = RepositorioDescuentosRecargos.DevolverPorId(vista.IdDescuentoRecargoCantidad);
            if (articulo.DescuentoRecargoCantidad == null)
                throw new Exception("El descuento y recargo por cantidad no existe");
            articulo.TipoComision = RepositorioTiposComisionesArticulos.DevolverPorId(vista.IdTipoComisionArticulo);
            if (articulo.TipoComision == null)
                throw new Exception("El tipo de comisión no existe");
            articulo.TipoImpuesto = RepositorioTiposImpuestosArticulos.DevolverPorId(vista.IdTipoImpuestoArticulo);
            if (articulo.TipoImpuesto == null)
                throw new Exception("El tipo de impuesto no existe");
            articulo.TipoCosto = RepositorioTiposCostosArticulos.DevolverPorId(vista.IdTipoCostoArticulo);
            if (articulo.TipoCosto == null)
                throw new Exception("El tipo de costo no existe");
            articulo.DescuentoRecargoFechaHora = RepositorioPromociones.DevolverPorId(vista.IdDescuentoRecargoFechaHora);
            if (articulo.DescuentoRecargoFechaHora == null)
                throw new Exception("El descuento y recargo por fecha y hora no existe");

            articulo.Codigo = vista.Codigo.Trim();
            articulo.Nombre = vista.Nombre.Trim();
            articulo.ExistenciaMinima = vista.ExistenciaMinima;
            articulo.ExistenciaMaxima = vista.ExistenciaMaxima;
            articulo.Costo = vista.Costo;

            switch ((EnumTiposComisionesArticulos)articulo.TipoComision.Id)
            {
                case EnumTiposComisionesArticulos.SinComision:
                case EnumTiposComisionesArticulos.ComisionVendedor:
                    articulo.Comision = 0;
                    articulo.ComisionMaxima = 0;
                    break;
                case EnumTiposComisionesArticulos.PorcentajeVenta:
                case EnumTiposComisionesArticulos.PorcentajeGanancia:
                    if (vista.Comision <= 0)
                        throw new Exception("La comisión no puede ser menor o igual a cero");
                    articulo.Comision = vista.Comision;
                    if (vista.Comision < 0)
                        throw new Exception("La comisión máxima no puede ser menor a cero");
                    articulo.ComisionMaxima = vista.ComisionMaxima;
                    break;
                case EnumTiposComisionesArticulos.MontoFijo:
                    if (vista.Comision <= 0)
                        throw new Exception("La comisión no puede ser menor o igual a cero");
                    articulo.Comision = vista.Comision;
                    articulo.ComisionMaxima = 0;
                    break;
                default:
                    break;
            }

            articulo.Iva = vista.Iva;
            articulo.Impuesto = vista.Impuesto;
            articulo.Observaciones = vista.Observaciones.Trim();
            articulo.Imagen = vista.Imagen;

            var registro = new Registro();
            registro.Usuario = usuario;
            if (vista.IdArticulo == 0)
                registro.Evento = RepositorioEventos.DevolverPorId((Byte)EnumEventos.ArticulosAlta);
            else
                registro.Evento = RepositorioEventos.DevolverPorId((Byte)EnumEventos.ArticulosModificacion);
            if (registro.Evento == null)
                throw new Exception("El evento no existe");

            if (vista.IdArticulo == 0)
                RepositorioArticulos.Insertar(articulo);
            else
            {
                RepositorioArticulos.Modificar(articulo);
                RepositorioArticulos.EliminarCamposPersonalizadosPorArticulo(articulo);
                RepositorioArticulos.EliminarListasPreciosComprasPorArticulo(articulo);
                RepositorioArticulos.EliminarListasPreciosVentasPorArticulo(articulo);
                if (vista.VariantesModificado)
                    RepositorioArticulos.EliminarVariantesPorArticulo(articulo);
                if (vista.VariantesModificado | vista.ExistenciasModificado)
                    RepositorioArticulos.EliminarExistenciasPorArticulo(articulo);
                RepositorioArticulos.EliminarProveedoresPorArticulo(articulo);
            }
            RepositorioRegistros.Insertar(registro, articulo);

            foreach (var item in vista.ListadoCamposPersonalizados)
                if (!String.IsNullOrWhiteSpace(item.Valor))
                {
                    item.Entidad = RepositorioCamposPersonalizadosArticulos.DevolverPorId(item.Entidad.Id);
                    if (item.Entidad != null)
                        RepositorioArticulos.InsertarCampoPersonalizado(articulo, item);
                }

            foreach (var item in vista.ListadoListasPreciosCompras)
                if (item.Valor > 0)
                {
                    item.Entidad = RepositorioListasPreciosCompras.DevolverPorId(item.Entidad.Id);
                    if (item.Entidad != null)
                        RepositorioArticulos.InsertarListaPrecioCompra(articulo, item);
                }

            foreach (var item in vista.ListadoListasPreciosVentas)
                if (item.Valor > 0)
                {
                    item.Entidad = RepositorioListasPreciosVentas.DevolverPorId(item.Entidad.Id);
                    if (item.Entidad != null)
                        RepositorioArticulos.InsertarListaPrecioVenta(articulo, item);
                }

            if (vista.VariantesModificado)
                foreach (var item in vista.ListadoVariantes)
                {
                    RepositorioArticulos.InsertarVariante(articulo, item);
                    foreach (var detalle in item.Valores)
                        RepositorioArticulos.InsertarVarianteDetalle(item, detalle);
                }

            if (vista.VariantesModificado | vista.ExistenciasModificado)
                foreach (var item in vista.ListadoExistencias)
                {
                    RepositorioArticulos.InsertarExistencia(articulo, item);
                    foreach (var detalle in item.VariantesDetalles)
                        RepositorioArticulos.InsertarExistenciaDetalle(item, detalle);
                }

            foreach (var item in vista.ListadoProveedores)
            {
                var proveedor = RepositorioProveedores.DevolverPorId(item.Id);
                if (proveedor != null)
                    RepositorioArticulos.InsertarProveedor(articulo, proveedor);
            }
        }

        public void ProveedorAgregar()
        {
            var proveedor = RepositorioProveedores.DevolverPorId(vista.ProveedorId);
            if (vista.ListadoProveedores.Exists(x => x.Id == vista.ProveedorId))
                throw new Exception("El proveedor ya está asociado al artículo");
            if (proveedor == null)
                throw new Exception("El proveedor no existe");

            var listado = vista.ListadoProveedores.ToList();
            listado.Add(proveedor);
            vista.ListadoProveedores = listado;
        }

        public void ProveedorQuitar()
        {
            var listadoNuevo = new List<Proveedor>();
            foreach (var item in vista.ListadoProveedores)
                if (item.Id != vista.ProveedorId)
                    listadoNuevo.Add(item);
            vista.ListadoProveedores = listadoNuevo;
        }

        public void VarianteAgregar()
        {
            if (String.IsNullOrWhiteSpace(vista.VarianteNombre))
                throw new Exception("El nombre de la variante no puede quedar vacío");
            if (vista.VarianteValores.Count == 0)
                throw new Exception("La variante debe tener al menos un valor");
            if (vista.ListadoVariantes.Exists(x => x.Nombre.Trim().ToLower() == vista.VarianteNombre.Trim().ToLower()))
                throw new Exception("Ya existe una variante con el mismo nombre");

            var contador = 1;
            var varianteNueva = new ArticuloVariante();
            varianteNueva.Id = contador;
            varianteNueva.Nombre = vista.VarianteNombre.Trim();
            varianteNueva.Valores = new List<ArticuloVarianteDetalle>();
            foreach (var valor in vista.VarianteValores)
                if (!String.IsNullOrWhiteSpace(valor) && !varianteNueva.Valores.Exists(x => x.Valor.Trim().ToLower() == valor.Trim().ToLower()))
                {
                    var varianteDetalle = new ArticuloVarianteDetalle();
                    varianteDetalle.Valor = valor.Trim();
                    varianteDetalle.Variante = varianteNueva;
                    varianteNueva.Valores.Add(varianteDetalle);
                }
            if (varianteNueva.Valores.Count == 0)
                throw new Exception("La variante debe tener al menos un valor valido");

            var listadoNuevo = new List<ArticuloVariante>();
            listadoNuevo.Add(varianteNueva);
            foreach (var item in vista.ListadoVariantes)
            {
                contador++;
                item.Id = contador;
                listadoNuevo.Add(item);
            }
            vista.ListadoVariantes = listadoNuevo;

            var listadoVariantes = ArticuloTipoSeleccion.GenerarListado(listadoNuevo, vista.ListadoUbicaciones);
            vista.TablaSeleccion = ArticuloTipoSeleccion.GenerarTabla(listadoVariantes, true, true);
            vista.ListadoSeleccion = listadoVariantes;
            vista.VariantesModificado = true;
        }

        public void VarianteQuitar()
        {
            var listadoNuevo = new List<ArticuloVariante>();
            foreach (var item in vista.ListadoVariantes)
                if (item.Id != vista.VarianteId)
                    listadoNuevo.Add(item);
            vista.ListadoVariantes = listadoNuevo;

            var listadoVariantes = ArticuloTipoSeleccion.GenerarListado(listadoNuevo, vista.ListadoUbicaciones);
            vista.TablaSeleccion = ArticuloTipoSeleccion.GenerarTabla(listadoVariantes, true, true);
            vista.ListadoSeleccion = listadoVariantes;
            vista.VariantesModificado = true;
        }

        public void VarianteEditar()
        {
            if (String.IsNullOrWhiteSpace(vista.VarianteNombre))
                throw new Exception("El nombre de la variante no puede quedar vacío");
            if (vista.VarianteValores.Count == 0)
                throw new Exception("La variante debe tener al menos un valor");
            if (vista.ListadoVariantes.Exists(x => x.Nombre.Trim().ToLower() == vista.VarianteNombre.Trim().ToLower() && x.Id != vista.VarianteId))
                throw new Exception("Ya existe una variante con el mismo nombre");

            var contador = 1;
            var varianteNueva = new ArticuloVariante();
            varianteNueva.Id = contador;
            varianteNueva.Nombre = vista.VarianteNombre.Trim();
            varianteNueva.Valores = new List<ArticuloVarianteDetalle>();
            foreach (var valor in vista.VarianteValores)
                if (!String.IsNullOrWhiteSpace(valor) && !varianteNueva.Valores.Exists(x => x.Valor.Trim().ToLower() == valor.Trim().ToLower()))
                {
                    var varianteDetalle = new ArticuloVarianteDetalle();
                    varianteDetalle.Valor = valor.Trim();
                    varianteDetalle.Variante = varianteNueva;
                    varianteNueva.Valores.Add(varianteDetalle);
                }
            if (varianteNueva.Valores.Count == 0)
                throw new Exception("La variante debe tener al menos un valor valido");

            var listadoQuitar = new List<ArticuloVariante>();
            foreach (var item in vista.ListadoVariantes)
                if (item.Id != vista.VarianteId)
                    listadoQuitar.Add(item);

            var listadoNuevo = new List<ArticuloVariante>();
            listadoNuevo.Add(varianteNueva);
            foreach (var item in listadoQuitar)
            {
                contador++;
                item.Id = contador;
                listadoNuevo.Add(item);
            }
            vista.ListadoVariantes = listadoNuevo;

            var listadoVariantes = ArticuloTipoSeleccion.GenerarListado(listadoNuevo, vista.ListadoUbicaciones);
            vista.TablaSeleccion = ArticuloTipoSeleccion.GenerarTabla(listadoVariantes, true, true);
            vista.ListadoSeleccion = listadoVariantes;
            vista.VariantesModificado = true;
        }

        public void ExistenciaEditar()
        {
            var listadoNuevo = new List<ArticuloExistencia>();

            var existenciaNueva = new ArticuloExistencia();
            var seleccion = vista.ListadoSeleccion.FirstOrDefault(x => x.Id == vista.IdDetalle);
            existenciaNueva.Cantidad = vista.ExistenciaCantidad;
            existenciaNueva.Ubicacion = seleccion.Ubicacion;
            existenciaNueva.VariantesDetalles = seleccion.VariantesDetalles;

            var existenciasActuales = vista.ListadoExistencias;
            foreach (var item in existenciasActuales)
                if (item.Ubicacion.Id == existenciaNueva.Ubicacion.Id)
                    if (!ArticuloTipoSeleccion.MismasVariantes(item.VariantesDetalles, existenciaNueva.VariantesDetalles))
                        listadoNuevo.Add(item);

            listadoNuevo.Add(existenciaNueva);

            var listadoVariantes = ArticuloTipoSeleccion.GenerarListado(vista.ListadoVariantes, vista.ListadoUbicaciones, listadoNuevo);
            vista.TablaSeleccion = ArticuloTipoSeleccion.GenerarTabla(listadoVariantes, true, true);
            vista.ListadoExistencias = listadoNuevo;

            vista.Existencia = listadoNuevo.Where(x => !x.EstaEliminado).Sum(x => x.Cantidad);
            vista.ExistenciasModificado = true;
        }

        #endregion
    }
}
